/**
 * date: 2018年3月5日
 * from  https://www.tslang.cn/docs/handbook/interfaces.html
 */

function printLabel(labelledObj: { label: string }) {
    console.log(labelledObj.label);
}

let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);

interface LabelledValue {
    label: string;
}

function printLabel102(labelledObj: LabelledValue) {
    console.log(labelledObj.label);
}

let myObj102 = {size: 10, label: "Size 10 Object"};
printLabel102(myObj102);

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig) : {color:string; area: number} {
    let newSquare = {color: "white", area: 100};
    if(config.color){
        newSquare.color = config.color;
    }
    if(config.width){
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "blcak"});

interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = {x: 10, y: 20};
// p1.x = 5; // error!

let a103: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a103;

// ro[0] = 12; // error!
// ro.push(5); // error!
// ro.length = 100; // error!
// a103 = ro; // error!

a103 = ro as number[]; // 可以用类型断言重写

// 最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 
// 做为变量使用的话用 const，若做为属性则使用readonly。

// 额外的属性检查: 如果一个对象字面量存在任何"目标类型"不包含的属性时, 你会得到一个错误。
// 绕开这些检查非常简单。最简单的方法是

let mySquare102 = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);

// 然而, 最佳方式是能够添加一个字符串索引签名……

interface SquareConfig102 {
    color?: string;
    width?: number;
    [propName: string]: any;
}

interface SearchFunc {
    (source: string, subString: string) : boolean;
}

let mySearch: SearchFunc;
mySearch = function(source:string, subString:string){
    let result = source.search(subString);
    return result > -1;
}

let mySearch102 : SearchFunc;
mySearch102 = function(src:string, sub: string): boolean {
    let result = src.search(sub);
    return result > -1;
}

interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

class Animal {
    name: string;
}

class Dog extends Animal {
    breed: string;
}
// 错误: 使用'string'索引, 有时会得到Animal!
interface NotOkay {
//    [x: number] : Animal;
    [x: string] : Dog;
}

interface NumberDictionary {
    [index: string] : number;
    length: number;     // 可以, length是number类型
//    name: string;       // 错误, `name`的类型与索引类型返回值的类型不匹配
}

interface ReadonlyStringArray {
    readonly [index: number]: string;
}

let myArray102 : ReadonlyStringArray = ["Alice", "Bob"];
// myArray102[2] = "Mallory"; // error!

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) {}
}

interface ClockInterface102 {
    currentTime: Date;
    setTime(d: Date);
}

class Clock102 implements ClockInterface102 {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) {}
}

interface ClockConstructor {
    new (hour: number, minute: number);
}

// class Clock103 implements ClockConstructor {
//     currentTime: Date;
//     constructor(h: number, m: number) {}
// }

interface ClockConstructor104 {
    new (hour: number, minute: number): ClockInterface104;
}
interface ClockInterface104 {
    tick();
}

function createClock(ctor: ClockConstructor104, hour: number, minute: number): ClockInterface104 {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface104 {
    constructor(h:number, m: number){}
    tick(){
        console.log("beep beep");
    }
}

class AnalogClock implements ClockInterface104 {
    constructor(h:number, m:number){}
    tick(){
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;

interface Shape103 {
    color : string;
}
interface PenStroke103 {
    penWidth: number;
}
interface Square103 extends Shape103, PenStroke103 {
    sideLength: number;
}

let square103 = <Square103>{};
square103.color = "blue";
square103.sideLength = 10;
square103.penWidth = 5.0;

interface Counter {
    (start : number) : string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start:number) {};
    counter.interval = 123;
    counter.reset = function() {};
    return counter;
}

let c104 = getCounter();
c104(10);
c104.reset();
c104.interval = 5.0;

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() {}
}

class TextBox extends Control {}

// class Image implements SelectableControl {
//     select() {}
// }

class Location105 {

}


